using UnityEngine;
using System.Collections;

[RequireComponent (typeof(BoxCollider))]
public class PlayerPhysics : MonoBehaviour {

	private PlayerController playerController;
	public LayerMask hardCollisionMask;
	public LayerMask softCollisionMask;
	public LayerMask damageCollisionMask;
	public LayerMask movableCollisionMask;

	public BoxCollider activeCollider;

	public Vector3 s;
	public Vector3 c;
	
	private Vector3 originalSize;
	private Vector3 originalCentre;
	private float colliderScale;
	
	private int collisionDivisionsX = 3;
	public int collisionDivisionsY =10;

	private float skin = .005f;
	
	[HideInInspector]
	public float deltaY;
	public float deltaX;
	[HideInInspector]
	public bool movementStopped;
	
	public Ray ray;
	public RaycastHit hit;

	void Start() {
		playerController = GetComponent<PlayerController>();

		colliderScale = transform.localScale.x;


	}

	public static float dir=1;
	public float oldDir=1;


	public Vector2 p;


	public void Move(Vector2 moveAmount) {




		deltaY = moveAmount.y;
		deltaX = moveAmount.x;
		float dir = Mathf.Sign(deltaY);
		p = transform.position;

		LayerMask verticalLayerToCheck = hardCollisionMask;
		if (dir < 0) {
			verticalLayerToCheck |= softCollisionMask;
		}

		playerController.st_grounded = false;

		
		for (int i = 0; i<collisionDivisionsX; i ++) {
		// Check collisions above and below
			float x = (p.x + c.x - s.x/2) + s.x/(collisionDivisionsX-1) * i; // Left, centre and then rightmost point of collider
			float y = p.y + c.y + s.y/2 * dir; // Bottom of collider
			
			ray = new Ray(new Vector2(x,y), new Vector2(0,dir));
			Debug.DrawRay(ray.origin,ray.direction);

			if (Physics.Raycast(ray,out hit,Mathf.Abs(deltaY) + skin, verticalLayerToCheck)) {
				// Get Distance between player and ground
				float dst = Vector3.Distance (ray.origin, hit.point);
				
				// Stop player's downwards movement after coming within skin width of a collider
				if (dst > skin) {
					deltaY = dst * dir - skin * dir;
				}
				else {
					deltaY = 0;
				}
				
				playerController.st_grounded = true;
				break;
				
			}

			if (Physics.Raycast(ray,out hit,Mathf.Abs(deltaY) + skin,damageCollisionMask)) {
				// Get Distance between player and ground
				Debug.Log("muereee");
				break;
				
			}

			if (Physics.Raycast(ray,out hit,Mathf.Abs(deltaY) + skin,softCollisionMask) && gameObject.layer != LayerMask.NameToLayer("Player")) {
				LayerChange(transform,"Player");
			}else if (playerController.st_grounded){
				LayerChange(transform,"Default");
			} 
		}
		
		
		// Check collisions left and right
		movementStopped = false;

		for (int i = 0; i<collisionDivisionsY; i ++) {
			dir=moveAmount.x;
			
			if(moveAmount.x>0){
				dir=1;
			} else {
				if(moveAmount.x<0) {
					dir=-1;
				} else {
					dir=0;
				}
			}
			
			float x = p.x + (c.x + s.x/2) * dir ;
			float y = (p.y + c.y - s.y/2) + s.y/(collisionDivisionsY-1) * i;
			
			ray = new Ray(new Vector2(x,y), new Vector2(dir,0));
			//Debug.DrawRay(ray.origin,ray.direction*(Mathf.Abs(activeCollider.size.x) + skin), Color.white, Time.deltaTime, false);

			if (Physics.Raycast(ray,out hit,(Mathf.Abs(deltaX) + skin), hardCollisionMask)) {
				// Get Distance between player and ground
				float dst = Vector3.Distance (ray.origin, hit.point);
				
				// Stop player's downwards movement after coming within skin width of a collider
				if (dst > skin) {
					deltaX = dst * dir - skin * dir;
				} else {
					deltaX = 0;
				}

				movementStopped = true;
				break;
				
			}  

			if(Physics.Raycast(ray,out hit,Mathf.Abs(deltaX) + skin, movableCollisionMask)){
			// Get Distance between player and ground
				float dst = Vector3.Distance (ray.origin, hit.point);
				
				// Stop player's downwards movement after coming within skin width of a collider
				if (!playerController.st_grab) {
					if (dst > skin) {
						deltaX = dst * dir - skin * dir;
					} else {
						deltaX = 0;
					}
				} else {

				}

				movementStopped = true;
				break;
			}

			if (Physics.Raycast(ray,out hit,Mathf.Abs(deltaX) + skin,softCollisionMask) && gameObject.layer != LayerMask.NameToLayer("Player")) {
				LayerChange(transform,"Player");
			}else if (playerController.st_grounded){
				LayerChange(transform,"Default");
			}

		}

		if (!playerController.st_grounded && !movementStopped) {
			Vector3 playerDir = new Vector3(deltaX,deltaY);
			Vector3 o = new Vector3(p.x + c.x + s.x/2 * Mathf.Sign(deltaX),p.y + c.y + s.y/2 * Mathf.Sign(deltaY));
			ray = new Ray(o,playerDir.normalized);

			if (Physics.Raycast(ray,Mathf.Sqrt(deltaX * deltaX + deltaY * deltaY),hardCollisionMask)) {
				playerController.st_grounded = true;
				deltaY = 0;
			}
		}

				if (playerController.activeCharacter == PlayerController.CHARS.ATHOR) {
		activeCollider = playerController.colliderAthor;
				} else {
					activeCollider = playerController.colliderLilith;
				}
		
		originalSize = activeCollider.size;
		originalCentre = activeCollider.center;
		
		SetCollider(originalSize,originalCentre);

		Vector2 finalTransform = new Vector2(deltaX,deltaY);

		transform.Translate(finalTransform,Space.World);


		if (playerController.st_grab) {
				playerController.movableObject.Translate (finalTransform, Space.World);
		}
	}


	public RaycastHit CheckHit(float hitDistance) {
		Vector3 p = transform.position;
		RaycastHit hitInfo = new RaycastHit();
		for (int i = 0; i < collisionDivisionsY; i++) {
			float x = p.x + c.x + s.x/2 * (-transform.right.x);
			float y = p.y + c.y - s.y/2 + s.y/(collisionDivisionsY-1) * i;

			Debug.DrawRay(new Vector2(x,y), -transform.right, Color.red);

			if (Physics.Raycast(new Vector2(x, y), -transform.right, out hitInfo, hitDistance)) {
				return hitInfo;
			}
		}

		return hitInfo;
	}
	// Set collider
	public void SetCollider(Vector3 size, Vector3 centre) {
		activeCollider.size = size;
		activeCollider.center = centre;
		
		s = size * colliderScale;
		c = centre * colliderScale;
	}
	
	public void ResetCollider() {
		SetCollider(originalSize,originalCentre);	
	}

	public void LayerChange(Transform objectNode, string layer){
		objectNode.gameObject.layer = LayerMask.NameToLayer(layer);
		foreach(Transform child in objectNode){
			if(child != null)	LayerChange (child,layer);
		}
	}
}
